﻿using System.Collections.Generic;
using System.IO;
using System.Xml;
using vJine.Core.Base;

namespace vJine.Core.IO.Xml {
    /// <summary>
    /// XML序列化、反序列化帮助类
    /// </summary>
    public partial class XmlHelper {
        /// <summary>
        /// 实例化帮助类
        /// </summary>
        public XmlHelper() {
        }
        /// <summary>
        /// 将实体类序列化为XML字符串或保存到指定的文件中
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="entity">实体实例</param>
        /// <param name="xml_file">要保存XML的文件</param>
        /// <returns>如果不指定xml_file则返回XML字符串</returns>
        public static string ToString<Tentity>(Tentity entity, string xml_file = null) where Tentity : class, new() {
            string Name = typeof(Tentity).Name;
            XmlDocument xmlDoc = XmlHelper.LoadXml(Name);
            XmlNode xmlRoot = xmlDoc.DocumentElement;

            XmlHelper.ToString<Tentity>(entity, xmlDoc, xmlRoot);

            if(string.IsNullOrEmpty(xml_file)) {
                return xmlDoc.InnerXml;
            } else {
                xmlDoc.Save(xml_file);
                return null;
            }
        }
        /// <summary>
        /// 将实体类集合序列化为XML字符串或保存到指定的文件中
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="entities">实体类集合</param>
        /// <param name="xml_file">要保存XML的文件</param>
        /// <returns>如果不指定xml_file则返回XML字符串</returns>
        public static string ToString<Tentity>(IList<Tentity> entities, string xml_file = null) where Tentity : class, new() {
            XmlDocument xmlDoc = XmlHelper.LoadXml("Items");
            XmlNode xmlRoot = xmlDoc.DocumentElement;

            XmlHelper.ToString<Tentity>(entities, xmlDoc, xmlRoot);

            if(string.IsNullOrEmpty(xml_file)) {
                return xmlDoc.InnerXml;
            } else {
                xmlDoc.Save(xml_file);
                return null;
            }
        }
        /// <summary>
        /// 将实体实例序列化到流
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="entity">实体类实例</param>
        /// <param name="xml_stream">XML流</param>
        public static void ToString<Tentity>(Tentity entity, Stream xml_stream) where Tentity : class, new() {
            string Name = typeof(Tentity).Name;
            XmlDocument xmlDoc = XmlHelper.LoadXml(Name);
            XmlNode xmlRoot = xmlDoc.DocumentElement;

            XmlHelper.ToString<Tentity>(entity, xmlDoc, xmlRoot);
            xmlDoc.Save(xml_stream);
        }
        /// <summary>
        /// 将实体实例集合序列化到流
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="entities">实体类集合</param>
        /// <param name="xml_stream">XML流</param>
        public static void ToString<Tentity>(IList<Tentity> entities, Stream xml_stream) where Tentity : class, new() {
            XmlDocument xmlDoc = XmlHelper.LoadXml("Items");
            XmlNode xmlRoot = xmlDoc.DocumentElement;

            XmlHelper.ToString<Tentity>(entities, xmlDoc, xmlRoot);

            xmlDoc.Save(xml_stream);
        }
        /// <summary>
        /// 反序列化XML文件或字符串为实例类
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="xml">XML文件或字符串</param>
        /// <param name="IsText">为False,xml参数被识别为文件，否则为字符串</param>
        /// <returns>实体类实例</returns>
        public static Tentity Parse<Tentity>(string xml, bool IsText = false) where Tentity : class, new() {
            XmlDocument xmlDoc = new XmlDocument();
            if(IsText) {
                xmlDoc.LoadXml(xml);
            } else {
                xmlDoc.Load(xml);
            }

            return XmlHelper.Parse<Tentity>(xmlDoc.DocumentElement);
        }
        /// <summary>
        /// 反序列化XML文件或字符串为实例类
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="xml">XML文件或XML字符串</param>
        /// <param name="entity">实体类实例</param>
        /// <param name="IsText">为False,xml参数被识别为文件，否则为字符串</param>
        public static void Parse<Tentity>(string xml, Tentity entity, bool IsText = false) where Tentity : class, new() {
            XmlDocument xmlDoc = new XmlDocument();
            if(IsText) {
                xmlDoc.LoadXml(xml);
            } else {
                xmlDoc.Load(xml);
            }

            XmlHelper.Parse<Tentity>(xmlDoc.DocumentElement, entity);
        }
        /// <summary>
        /// 反序列化XML文件或字符串为实例类集合
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="xml">XML文件或XML字符串</param>
        /// <param name="entities">XML实例集合</param>
        /// <param name="IsText">为False,xml参数被识别为文件，否则为字符串</param>
        public static void Parse<Tentity>(string xml, IList<Tentity> entities, bool IsText = false) where Tentity : class, new() {
            XmlDocument xmlDoc = new XmlDocument();

            if(IsText) {
                xmlDoc.LoadXml(xml);
            } else {
                xmlDoc.Load(xml);
            }

            XmlNode xmlRoot = xmlDoc.DocumentElement;
            XmlNode itemsNode = xmlDoc["Items"];
            if(itemsNode == null) {
                throw new CoreException("未找到Items节点");
            }
            XmlHelper.Parse<Tentity>(xmlDoc["Items"].ChildNodes, entities);
        }        
        /// <summary>
        /// 反序列化流为实体类实例
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="xml_stream">XML流</param>
        /// <returns>实体类实例</returns>
        public static Tentity Parse<Tentity>(Stream xml_stream) where Tentity : class, new() {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xml_stream);

            return XmlHelper.Parse<Tentity>(xmlDoc.DocumentElement);
        }
        /// <summary>
        /// 反序列化流为实体类实例
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="xml_stream">XML流</param>
        /// <param name="entity">实体类实例</param>
        public static void Parse<Tentity>(Stream xml_stream, Tentity entity) where Tentity : class, new() {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xml_stream);

            XmlHelper.Parse<Tentity>(xmlDoc.DocumentElement, entity);
        }

        static XmlDocument LoadXml(string Name) {
            XmlDocument xmlDoc = new XmlDocument();
            if(string.IsNullOrEmpty(Name)) {
                xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
            } else {
                xmlDoc.LoadXml(
                    string.Format("<?xml version=\"1.0\" encoding=\"utf-8\" ?><{0}></{0}>", Name)
                    );
            }

            return xmlDoc;
        }
        /// <summary>
        /// 绑定实体类到指定的XML文件（反序列化实体类，并在实体类发生改变时序列至XML文件）
        /// </summary>
        /// <typeparam name="Tentity">实体类型</typeparam>
        /// <param name="xml_file">XML文件</param>
        /// <returns>实体类实例</returns>
        public static Tentity Bind<Tentity>(string xml_file) where Tentity : EntityBase, new() {
            Tentity newObj = null;
            if(!File.Exists(xml_file)) {
                newObj = new Tentity();
                XmlHelper.ToString<Tentity>(newObj, xml_file);
            } else {
                newObj = XmlHelper.Parse<Tentity>(xml_file);
            }
            
            newObj.PropertyChanged +=
                (object sender, System.ComponentModel.PropertyChangedEventArgs e) => {
                    XmlHelper.ToString<Tentity>(newObj, xml_file);
                };
            return newObj;
        }
    }
}